#pragma once

#include <condition_variable>
#include <deque>
#include <mutex>
#include <stdexcept>

/**
 * @brief 轻量级线程安全阻塞队列（Blocking Queue）。
 *
 * @tparam T 队列中存放的数据类型。
 *
 * @details
 *  - 采用互斥量 + 条件变量实现生产者/消费者协调。
 *  - 支持单/多生产者与单/多消费者的场景；但需调用方自行约束并发语义。
 *  - 通过 `close()` 方法显式通知消费者“后续不再有新任务”。
 */
template <typename T>
class BlockingQueue {
public:
    /**
     * @brief 向队列尾部推入一个元素。
     *
     * @param value 待插入的元素。
     *
     * @throws std::runtime_error 当队列已关闭时抛出异常。
     *
     * @note 插入成功后会唤醒一个等待的消费者线程。
     */
    void push(T value) {
        {
            std::lock_guard<std::mutex> lock(mutex_);
            if (closed_) {
                throw std::runtime_error("push on closed BlockingQueue");
            }
            queue_.push_back(std::move(value));
        }
        cv_.notify_one();
    }

    /**
     * @brief 从队列头部弹出一个元素。
     *
     * @param[out] out 用于接收弹出的元素。
     *
     * @return 若成功弹出元素返回 `true`；当队列关闭且无元素时返回 `false`。
     *
     * @note 若队列暂时为空，会阻塞等待直到出现新元素或队列被关闭。
     */
    bool pop(T& out) {
        std::unique_lock<std::mutex> lock(mutex_);
        cv_.wait(lock, [&] { return closed_ || !queue_.empty(); });
        if (queue_.empty()) {
            return false;
        }
        out = std::move(queue_.front());
        queue_.pop_front();
        return true;
    }

    /**
     * @brief 关闭队列。
     *
     * @post 关闭后禁止新的 push 操作，并唤醒全部等待线程。
     */
    void close() {
        {
            std::lock_guard<std::mutex> lock(mutex_);
            closed_ = true;
        }
        cv_.notify_all();
    }

private:
    std::mutex mutex_;                  ///< 保护共享状态的互斥量。
    std::condition_variable cv_;        ///< 生产者/消费者同步的条件变量。
    std::deque<T> queue_;               ///< 实际存储容器（双端队列）。
    bool closed_ = false;               ///< 队列是否已关闭。
};